import datetime
import json
from decimal import Decimal

from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.http import JsonResponse, HttpResponseForbidden, HttpResponseNotFound
from django.utils.timezone import localtime
from django_redis import get_redis_connection
from django.shortcuts import render
from django.views import View
from redis.client import Pipeline

from apps.goods.models import SKU, SPU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.response_code import RETCODE


# 提交订单页面信息
class OrdersSettlementView(LoginRequiredMixin, View):

    # 提交订单页面信息
    def get(self, request):
        user = request.user

        # 收货地址列表
        addresses = user.addresses.filter(is_deleted=False)
        # 购物车内的所有选中商品
        carts_cli = get_redis_connection('carts')
        seleceted = carts_cli.smembers(f"carts_selected_{user.id}")
        redis_carts_dict = carts_cli.hgetall(f"carts_{user.id}")
        skus = SKU.objects.filter(id__in=seleceted)
        carts_goods =[]
        total_amount = Decimal(0.00)
        total_count = 0
        for sku in skus:
            count = int(redis_carts_dict.get(str(sku.id).encode()))
            amount = sku.price * count,
            # 注意,amount类型为tuple
            total_count += count
            total_amount += amount[0]
            carts_goods.append({
                "default_image_url": sku.default_image.url,
                "name": sku.name,
                "price": sku.price,
                "count": count,
                "amount": amount[0],

            })

        freight = Decimal(10.00)
        payment_amount = total_amount + freight
        context = {
            "addresses": addresses,
            "carts_goods": carts_goods,
            "default_address_id": user.default_address_id,
            "total_count": total_count,
            "freight": 10,
            "total_amount": total_amount,
            "payment_amount": payment_amount
        }

        return render(request, 'place_order.html', context)


# 生成订单基本信息
class OrdersCommitView(LoginRequiredMixin, View):
    def post(self, request):
        json_dict = json.loads(request.body)
        address_id = json_dict.get('address_id')
        pay_method = json_dict.get('pay_method')

        # 校验参数
        try:
            addr = Address.objects.get(id=address_id)
            assert pay_method in OrderInfo.PAY_METHODS_ENUM.values()
        except Exception:
            return HttpResponseForbidden('请求参数错误')

        user = request.user

        # 生成订单编号 年月日时分秒+用户编号
        order_id = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + f'{user.id:09d}'

        # 开启一个mysql事物
        with transaction.atomic():
            # 创建回滚点
            save_point = transaction.savepoint()

            # 暴力回滚
            try:
                # 保存订单基本信息
                order_info = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=addr,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method
                )

                # 计算订单信息
                redis_cli = get_redis_connection('carts')
                carts_dict = redis_cli.hgetall(f'carts_{user.id}')
                selected = redis_cli.smembers(f'carts_selected_{user.id}')
                if not selected:
                    # 购物车为空
                    transaction.savepoint_rollback(save_point)
                    return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '您没有选中任何商品'})
                skus = SKU.objects.filter(id__in=selected)
                for sku in skus:
                    while True:
                        # 获取初始库存和销量
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        # 判断库存
                        count = int(carts_dict[str(sku.id).encode()])
                        if count > origin_stock:
                            # 库存不足,回滚
                            transaction.savepoint_rollback(save_point)
                            return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})

                        # 减少库存,增加销量
                        new_stock = origin_stock - count
                        new_sales = origin_sales + count
                        ret = SKU.objects.filter(id=sku.id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if ret == 0:  # 受影响行数为0,表示修改失败
                            continue

                        # 一一一一一一一一一一一一一一一一一一定要记得 改完了保存!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                        sku.spu.sales += count
                        sku.spu.save()

                        # 更新订单基本信息 order_info
                        order_info.total_count += count
                        this_amount = sku.price * count
                        order_info.total_amount += this_amount

                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order=order_info,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )
                        break

                # 更新订单总金额(含邮费),保存订单更改
                order_info.total_amount += order_info.freight
                order_info.save()
            except Exception:
                transaction.savepoint_rollback(save_point)
                return JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})
            # 提交事务
            transaction.savepoint_commit(save_point)

        # 删除redis中已经提交订单的购物车信息
        p1:Pipeline = redis_cli.pipeline()
        p1.hdel(f'carts_{user.id}', *selected)
        p1.delete(f'carts_selected_{user.id}')
        p1.execute()

        # 响应提交订单结果
        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order_id})


# 提交订单成功页面
class OrdersSuccessView(LoginRequiredMixin, View):
    # orders/success/?order_id=&payment_amount=30760&pay_method=2
    def get(self, request):
        """跳转订单详情页面"""
        # 解析参数
        order_id = request.GET.get('order_id')
        payment_amount= request.GET.get('payment_amount')
        pay_method= request.GET.get('pay_method')
        # 校验参数
        try:
            order = OrderInfo.objects.get(order_id=order_id)
            payment_amount = Decimal(payment_amount)
            pay_method = int(pay_method)
            assert payment_amount == order.total_amount
            assert pay_method in OrderInfo.PAY_METHODS_ENUM.values()
        except Exception as e:
            # settings.LOGGER.error('跳转订单详情界面参数错误', e)
            return HttpResponseForbidden('参数错误')

        context = {
            "total_amount": order.total_amount,
            "order_id": order_id,
            "pay_method": pay_method,
        }
        return render(request, 'order_success.html', context)


# 订单评价
class OrdersCommentView(LoginRequiredMixin, View):
    def get(self, request):
        # 校验参数
        try:
            order_id = request.GET.get('order_id')
            order = OrderInfo.objects.get(order_id=order_id, status=OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"])
        except:
            return HttpResponseNotFound('您访问的订单不存在')
        order_suk_id_lst = [order_good.sku_id for order_good in order.skus.filter(is_commented=False)]
        skus = [{
            "sku_id": sku.id,
            "name": sku.name,
            "price": str(sku.price),
            "default_image_url": sku.default_image.url,
            "order_id": order_id
        } for sku in SKU.objects.filter(id__in=order_suk_id_lst)]

        context = {"skus": skus}
        return render(request, 'goods_judge.html', context)

    def post(self, request):
        """
        提交评价
        """
        # 1 接收校验参数
        data_dict = json.loads(request.body)
        order_id = data_dict.get("order_id")
        sku_id = data_dict.get("sku_id")
        comment = data_dict.get("comment")
        score = data_dict.get("score", 5)
        is_anonymous = data_dict.get("is_anonymous")
        try:
            order_good = OrderGoods.objects.filter(order_id=order_id, sku_id=sku_id, is_commented=False)
            assert order_good, "订单商品不存在,或已评价"
            assert comment.__len__() >= 5, "评论长度小于5"
            assert 0 <= int(score) <= 5, "评价分值信息错误"
            assert isinstance(is_anonymous, bool), "匿名评价状态错误"
        except Exception as e:
            return JsonResponse({"code": RETCODE.USERERR, "errmsg": str(e)})

        # 开启mysql事务, 写入评价信息
        with transaction.atomic():
            try:
                sku = order_good[0].sku
                sku_comments = sku.comments
                spu_id, spu_comments = sku.spu.id, sku.spu.comments
                # 2 OrderGoods表写入评价数据 filter(order_id, sku_id)
                order_good.update(comment=comment, score=int(score), is_anonymous=is_anonymous, is_commented=True)
                # 3 修改订单状态, 如果订单下的商品全部已评价 --> ORDER_STATUS_ENUM["FINISHED"]
                if all([order_good.is_commented for order_good in OrderGoods.objects.filter(order_id=order_id)]):
                    OrderInfo.objects.filter(order_id=order_id).update(status=OrderInfo.ORDER_STATUS_ENUM["FINISHED"])
                # 4 sku 和 spu的评论数量+1
                sku_comments += 1
                spu_comments += 1
                SKU.objects.filter(id=sku_id).update(comments=sku_comments)
                SPU.objects.filter(id=spu_id).update(comments=spu_comments)
            except Exception as e:
                settings.LOGGER.error('用户评价失败', e)
                transaction.rollback()
                return JsonResponse({"code": RETCODE.DBERR, "errmsg": "评价失败"})

        transaction.commit()
        return JsonResponse({"code": RETCODE.OK, "errmsg": "OK"})
